﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using CNKI.TPI.Web.Base;
using CNKI.TPI.Web.Search.IBLL;
using CNKI.TPI.Web.Search.IDAO;
using CNKI.TPI.Web.Search.Model;
using CNKI.TPI.Web.Admin.IBLL;
using Autofac.Integration.Mvc;
using System.Web.Mvc;

namespace CNKI.TPI.Web.Search.BLL
{
    public enum SecurityType
    {
        Null = 0,
        Above = 1,
        Spec = 2,
    };
    class UserService : BaseService, IUserService
    {
        private IUserDAO userDao = null;
        private ICategoryDAO categoryDAO = null;
        private IUserDBDAO userDBDAO = null;

        public UserService(IUserDAO userDao, ICategoryDAO categoryDAO, IUserDBDAO userDBDAO)
        {
            this.userDao = this.generator.CreateInterfaceProxyWithTarget<IUserDAO>(userDao, new IInterceptor[] { new LogInterceptor() });
            this.categoryDAO = this.generator.CreateInterfaceProxyWithTarget<ICategoryDAO>(categoryDAO, new IInterceptor[] { new LogInterceptor() });
            this.userDBDAO = this.generator.CreateInterfaceProxyWithTarget<IUserDBDAO>(userDBDAO, new IInterceptor[] { new LogInterceptor() });
        }

        /// <summary>
        /// 验证用户
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public LoginUserInfo ValidateUser(string userName, string password, bool needPWD = true)
        {
            LogOpr.Debug("开始执行ValidateUser");
            LoginUserInfo result = new LoginUserInfo();
            try
            {
                if (ConfigHelper.IsOAAccountEnabled() && needPWD && !userName.ToLower().Equals("sa"))
                {
                    LogOpr.Debug("开始执行ValidateUserByRemoteServer");
                    if (ValidateUserByRemoteServer(userName, password))
                    {
                        password = "";
                    }
                    else
                    {
                        result.status = LoginUserInfo.MessageFlage.PasswordError;
                        LogOpr.Login(userName, ((int)result.status).ToString());
                        return result;
                    }
                }

                password = null == password ? "" : password;
                SYS_CMS_USER userinfo = userDao.GetUser(userName);
                if (null != userinfo && (password.Equals(userinfo.Password) || !needPWD))
                {
                    if (userinfo.StopFlag == 1)
                    {
                        result.status = LoginUserInfo.MessageFlage.StopError;
                        LogOpr.Login(userName, ((int)result.status).ToString());
                        return result;
                    }
                    if (!string.IsNullOrEmpty(userinfo.EndDate) && DateTime.Parse(userinfo.EndDate + " 23:59:59") < DateTime.Now)
                    {
                        result.status = LoginUserInfo.MessageFlage.Expire;
                        LogOpr.Login(userName, ((int)result.status).ToString());
                        return result;
                    }
                    IList<SYS_CMS_USER_IP> userIPList = userDao.GetUserIP(userinfo.SysID);
                    result.UserID = userinfo.SysID.ToString();
                    result.UserCode = userinfo.Username;
                    result.UserName = userinfo.RealName;
                    result.password = userinfo.Password;
                    //初始化角色权限
                    ProcessRole(result);
                    //验证用户ip
                    bool isInIPRange = CheckIP(userIPList);
                    if (!isInIPRange)
                    {
                        //如果用户ip验证没通过，验证对应角色所设置的ip
                        if (result.Role != null && result.Role.Count > 0)
                        {
                            userIPList = userDao.GetGroupIP(result.Role.Select(c => c.SysID).ToList());
                            isInIPRange = CheckIP(userIPList);
                        }
                    }

                    if (isInIPRange)
                    {
                        System.Web.HttpContext.Current.Session.Clear();
                        //初始化密级
                        ProcessSecurity(result, userinfo);
                        //初始化数据权限
                        ProcessDBRight(result);

                    }
                    else
                    {
                        result.status = LoginUserInfo.MessageFlage.IpError;
                        LogOpr.Login(userName, ((int)result.status).ToString());
                        return result;
                    }
                }
                else
                {
                    result.status = LoginUserInfo.MessageFlage.PasswordError;
                    LogOpr.Login(userName, ((int)result.status).ToString());
                    return result;
                }
            }
            catch (Exception ex)
            {
                LogOpr.Error(ex.ToString());
            }
            LogOpr.Login(userName, ((int)result.status).ToString());
            return result;
        }

        public bool CheckUser(SYS_CMS_USER user)
        {
            bool result = true;
            try
            {
                SYS_CMS_USER userinfo = userDao.GetUser(user.Username);
                if (null == userinfo)
                {
                    LogOpr.Debug("OA账号在系统中不存在");
                    IUserMgmtService userMgmtService = AutofacDependencyResolver.Current.GetService<IUserMgmtService>();
                    int status = userMgmtService.SaveUserInfo(user, new List<SYS_CMS_USER_GROUP>() { new SYS_CMS_USER_GROUP() { GroupID = 4 } }, new List<SYS_CMS_USER_IP>() { new SYS_CMS_USER_IP() { SIP = "0.0.0.0", EIP = "255.255.255.255", Flag = 0 } });
                    if (status == 1)
                    {
                        LogOpr.Debug("OA账号创建成功");
                    }
                    else
                    {
                        LogOpr.Debug("OA账号创建失败");
                        result = false;
                    }
                }
            }
            catch (Exception ex)
            {
                LogOpr.Error(ex.ToString());
            }
            return result;
        }
        private bool ValidateUserByRemoteServer(string username, string password)
        {
            bool result = false;
            string message = "";
            DataTable userTable = null;
            try
            {
                LogOpr.Debug("开始验证OA账号");
                if (OAAuthenticationProvider.ValidateUser(username, password, "", out message, out userTable))
                {
                    LogOpr.Debug("验证OA账号成功");
                    SYS_CMS_USER userinfo = userDao.GetUser(username);
                    if (null == userinfo)
                    {
                        LogOpr.Debug("OA账号在系统中不存在");
                        userinfo = OAAuthenticationProvider.GetUserInfo(userTable);
                        IUserMgmtService userMgmtService = AutofacDependencyResolver.Current.GetService<IUserMgmtService>();
                        int status = userMgmtService.SaveUserInfo(userinfo, new List<SYS_CMS_USER_GROUP>() { new SYS_CMS_USER_GROUP() { GroupID = 4 } }, new List<SYS_CMS_USER_IP>() { new SYS_CMS_USER_IP(){ SIP="0.0.0.0", EIP="255.255.255.255", Flag=0}});
                        if (status == 1)
                        {
                            LogOpr.Debug("OA账号创建成功");
                        }
                        else
                        {
                            LogOpr.Debug("OA账号创建失败");
                        }
                    }
                    result = true;
                }
            }
            catch (Exception ex)
            {
                LogOpr.Error(ex.ToString());
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userIPList"></param>
        /// <returns></returns>
        private static bool CheckIP(IList<SYS_CMS_USER_IP> userIPList)
        {
            bool isInIPRange = false;
            string clientIP = IPUntil.GetIP();
            foreach (SYS_CMS_USER_IP item in userIPList)
            {
                isInIPRange = IPUntil.IsInIPRange(item.SIP, item.EIP, clientIP);
                if (isInIPRange)
                {
                    break;
                }
            }
            return isInIPRange;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userInfo"></param>
        private void ProcessRole(LoginUserInfo userInfo)
        {
            IList<SYS_CMS_USER_GROUP> userGroup = userDao.GetUserGroup(userInfo.UserID);
            userInfo.Role = userDao.GetGroup(userGroup.Select(c => c.GroupID));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userInfo"></param>
        private void ProcessDBRight(LoginUserInfo userInfo)
        {
            //查找用户数据库权限
            IList<SYS_CMS_USER_ACL_DB_RIGHT> userDBRightList = userDao.GetDBRight(userInfo.UserID, RightType.User);
            //按照密级过滤数据库
            IList<SYS_CMS_USER_ACL_DB_RIGHT> filteredUserDBList = FilterDB(userInfo, userDBRightList);
            //查找用户所在角色的数据库权限
            IList<SYS_CMS_USER_ACL_DB_RIGHT> groupDBRightList = userDao.GetGroupDBRight(userInfo.Role.Select(c => c.SysID).ToList());
            //按照密级过滤数据库
            IList<SYS_CMS_USER_ACL_DB_RIGHT> filteredGroupDBList = FilterDB(userInfo, groupDBRightList);
            //获得数据库列表
            IList<SYS_CMS_DATABASE> dbList = userDBDAO.GetDatabaseList();

            UserDBInfo dbInfo = null;
            IList<SYS_CMS_USER_ACL_DB_RIGHT> dBList = null;
            foreach (SYS_CMS_USER_ACL_DB_RIGHT item in filteredUserDBList)
            {
                dBList = filteredGroupDBList.Where(c => c.DBID == item.DBID).ToList();
                foreach (SYS_CMS_USER_ACL_DB_RIGHT obj in dBList)
                {
                    filteredGroupDBList.Remove(obj);
                }
                dBList.Add(item);
                dbInfo = BuildDBRight(dBList, dbList);
                userInfo.DBInfo.Add(dbInfo);
            }
            if (filteredGroupDBList.Count > 0)
            {
                IEnumerable<int> dbIDlist = filteredGroupDBList.Select(c => c.DBID).Distinct();
                foreach (int dbID in dbIDlist)
                {
                    dBList = filteredGroupDBList.Where(c => c.DBID == dbID).ToList();
                    dbInfo = BuildDBRight(dBList, dbList);
                    userInfo.DBInfo.Add(dbInfo);
                }
            }

            //添加外部数据库访问权限
            IList<SYS_CMS_DATABASE> extDBInfoList = categoryDAO.GetDatabaseBySearchType(new List<SearchType>() { SearchType.CNKI, SearchType.KSPIRDER } );
            if (extDBInfoList != null)
            {
                foreach (SYS_CMS_DATABASE item in extDBInfoList)
                {
                    userInfo.DBInfo.Add(new UserDBInfo() { DBID = item.SysID, DownloadPerDay = 0, TotalDownload = 0, OperateFunc = -1 });
                }
            }
        }

        private UserDBInfo BuildDBRight(IList<SYS_CMS_USER_ACL_DB_RIGHT> dBList, IList<SYS_CMS_DATABASE> dbList)
        {
            SYS_CMS_USER_ACL_DB_RIGHT item = null;
            ISet<string> fieldSet = new HashSet<string>();
            UserDBInfo dbInfo = new UserDBInfo();
            SYS_CMS_USER_ACL_DB_RIGHT first = dBList[0];
            dbInfo.DBID = first.DBID;
            IList<SYS_CMS_DATABASE> targetDB = dbList.Where(c => c.SysID == first.DBID).ToList();
            if (targetDB != null && targetDB.Count > 0)
            {
                dbInfo.DBCode = targetDB[0].DatabaseCode;
            }
            dbInfo.DownloadPerDay = first.DownloadCountOfDay;
            dbInfo.TotalDownload = first.MaxDownloadCount;
            fieldSet = MergeField(fieldSet, first);
            dbInfo.OperateFunc = first.RightValue;
            dbInfo.Navi = first.RightClsValue;

            for (int i = 1; i < dBList.Count; i++)
            {
                item = dBList[i];
                dbInfo.DownloadPerDay = dbInfo.DownloadPerDay != 0 && item.DownloadCountOfDay > dbInfo.DownloadPerDay ? item.DownloadCountOfDay : dbInfo.DownloadPerDay;
                dbInfo.TotalDownload = dbInfo.TotalDownload != 0 && item.MaxDownloadCount > dbInfo.TotalDownload ? item.MaxDownloadCount : dbInfo.TotalDownload;
                fieldSet = MergeField(fieldSet, item);
                dbInfo.OperateFunc = MergeRightValue(dbInfo.OperateFunc, item.RightValue);
                if (!string.IsNullOrEmpty(dBList[i].RightClsValue))
                {
                    string nav = dBList[i].RightClsValue + ";";
                    dbInfo.Navi += nav;
                }
            }

            if (null != fieldSet)
            {
                dbInfo.Field = fieldSet.ToList();
            }
            dbInfo.Navi = dbInfo.Navi.TrimEnd(';');

            if (dbInfo.OperateFunc == -1)
            {
                dbInfo.Field = null;
                dbInfo.Navi = null;
            }
            return dbInfo;
        }

        private int MergeRightValue(int one, int two)
        {
            int result = 0;
            if (-1 == one || -1 == two)
            {
                result = -1;
            }
            else
            {
                result = one | two;
            }
            return result;
        }

        /// <summary>
        /// 合并字段权限
        /// </summary>
        /// <param name="fieldSet"></param>
        /// <param name="dbRight"></param>
        /// <returns></returns>
        private ISet<string> MergeField(ISet<string> fieldSet, SYS_CMS_USER_ACL_DB_RIGHT dbRight)
        {
            string[] tempFieldArray = null;
            if (-1 == dbRight.RightValue)
            {
                if (null != fieldSet)
                {
                    fieldSet.Clear();
                    fieldSet = null;
                }
            }
            else if (fieldSet != null)
            {
                tempFieldArray = dbRight.RightFieldName.Split(',').ToArray();
                foreach (string field in tempFieldArray)
                {
                    if (!fieldSet.Contains(field))
                    {
                        fieldSet.Add(field);
                    }
                }
            }
            return fieldSet;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="dbRightList"></param>
        private IList<SYS_CMS_USER_ACL_DB_RIGHT> FilterDB(LoginUserInfo userInfo, IList<SYS_CMS_USER_ACL_DB_RIGHT> dbRightList)
        {
            IList<SYS_CMS_USER_ACL_DB_RIGHT> result = new List<SYS_CMS_USER_ACL_DB_RIGHT>();
            try
            {
                //根据ID获得数据库信息
                IList<SYS_CMS_DATABASE> dblist = categoryDAO.GetDatabaseByID(dbRightList.Select(c => c.DBID).ToList());
                //根据用户密级信息过滤数据库信息
                dblist = dblist.Where(c => userInfo.Security.Contains(c.Secrity.ToString())).ToList();
                //根据过滤后的数据库信息过滤SYS_CMS_USER_ACL_DB_RIGHT
                IList<int> dbIDList = dblist.Select(i => i.SysID).ToList();
                result = dbRightList.Where(c => dbIDList.Contains(c.DBID)).ToList();
            }
            catch (Exception ex)
            {
                LogOpr.Error(ex.ToString());
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userInfo"></param>
        private void ProcessSecurity(LoginUserInfo userInfo, SYS_CMS_USER user)
        {
            IList<SYS_CMS_SECURITY> dbRightList = userDao.GetSecurityInfo();
            switch ((SecurityType)user.SecurityType)
            {
                case SecurityType.Null:
                    userInfo.Security = new List<string>();
                    userInfo.Security.Add("0");
                    break;
                case SecurityType.Above:
                    userInfo.Security = dbRightList.Where(c => (int.Parse(c.Value) <= int.Parse(user.SecurityValue))).Select(c => c.Value).ToList<string>();
                    break;
                case SecurityType.Spec:
                    userInfo.Security = user.SecurityValue.Split(',').ToList<string>();
                    break;
            }
        }

        public DataTable GetAllUser()
        {
            return userDao.GetAllUser();
        }

              /// <summary>
        /// 获取登录失败次数
        /// </summary>
        /// <returns></returns>
        public int GetFaidNum()
        {
            return userDao.GetFaidNum();
        }
    }
}
